//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <string.h>
#include "marshal.h"
#include "prxstub.h"
#include "rot.h"

#define ROT_HASHMASK_BIT    5

#define ROT_HASHMASK        ((1 << ROT_HASHMASK_BIT) - 1)
#define ROT_HASHTABLE_SIZE  (1 << ROT_HASHMASK_BIT)
#define ROT_HASH_GETOIDINDEX(oid_t)  (oid_t & ROT_HASHMASK)

//CriticalSection g_importTableLock;
//CriticalSection g_exportTableLock;
//CriticalSection g_marshalLock;

PVoid g_importTableLock = NULL;
PVoid g_exportTableLock = NULL;
PVoid g_marshalLock     = NULL;

static ImportObject s_hashImportObjects[ROT_HASHTABLE_SIZE];
static ExportObject s_hashExportObjects[ROT_HASHTABLE_SIZE];

ECode InitializeROT()
{
    for (int n = 0; n < ROT_HASHTABLE_SIZE; n++) {
        s_hashImportObjects[n].Initialize();
        s_hashImportObjects[n].m_oid = 0;
        s_hashImportObjects[n].m_pNext = NULL;
        s_hashExportObjects[n].Initialize();
        s_hashExportObjects[n].m_oid = 0;
        s_hashExportObjects[n].m_pNext = NULL;
    }
    AuraCriticalSection_Create(&g_importTableLock);
    AuraCriticalSection_Create(&g_exportTableLock);
    AuraCriticalSection_Create(&g_marshalLock);

    //EzInitializeCriticalSection(&g_importTableLock);
    //EzInitializeCriticalSection(&g_exportTableLock);
    //EzInitializeCriticalSection(&g_marshalLock);

    return NOERROR;
}

void DestroyROT()
{
    AuraCriticalSection_Destroy(g_importTableLock);
    AuraCriticalSection_Destroy(g_exportTableLock);
    AuraCriticalSection_Destroy(g_marshalLock);

    return ;
}

ECode RegisterExportObject(
    /* [in] */ oid_t oid,
    /* [in] */ IInterface *pObject,
    /* [in] */ IStub *pIStub)
{
    ExportObject* pObjNode;

    pObject = IInterface::ProbeDefault(pObject);
    if (!pObject) {
        return E_NO_INTERFACE;
    }

    pObjNode = new ExportObject;
    if (NULL == pObjNode) return E_OUT_OF_MEMORY;
    pObjNode->m_oid = oid;
    pObjNode->m_pObject = pObject;
    pObjNode->m_pIStub = pIStub;

    AuraCriticalSection_Enter(g_exportTableLock);
    s_hashExportObjects[ROT_HASH_GETOIDINDEX(oid)].InsertFirst(pObjNode);
    AuraCriticalSection_Leave(g_exportTableLock);
    return NOERROR;
}

ECode FindExportObject(
    /* [in] */ IInterface *pObject,
    /* [out] */ ExportObject *pExport)
{
    pObject = IInterface::ProbeDefault(pObject);
    if (!pObject) {
        return E_NO_INTERFACE;
    }

    AuraCriticalSection_Enter(g_exportTableLock);
    ExportObject* pIter;
    for (int n = 0; n < ROT_HASHTABLE_SIZE; n++) {
        pIter = s_hashExportObjects + n;
        for (; NULL != pIter; pIter = (ExportObject*)(pIter->Next())) {
            if (pIter->m_oid != 0 && pIter->m_pObject == pObject) {
                memcpy(pExport, pIter, sizeof(ExportObject));
                pExport->m_pIStub->AddRef();
                AuraCriticalSection_Leave(g_exportTableLock);
                return NOERROR;
            }
        }
    }

    AuraCriticalSection_Leave(g_exportTableLock);
    return E_NO_EXPORT_SERVER;
}

ECode FindExportObject(
    /* [in] */ oid_t oid,
    /* [out] */ ExportObject *pExport)
{
    AuraCriticalSection_Enter(g_exportTableLock);
    ExportObject* pHead = s_hashExportObjects + ROT_HASH_GETOIDINDEX(oid);

    for (ExportObject* pIter = pHead; NULL != pIter; \
        pIter = (ExportObject*)(pIter->Next())) {
        if (pIter->m_oid == oid) {
            memcpy(pExport, pIter, sizeof(ExportObject));
            pExport->m_pIStub->AddRef();
            AuraCriticalSection_Leave(g_exportTableLock);
            return NOERROR;
        }
    }

    AuraCriticalSection_Leave(g_exportTableLock);
    return E_NO_EXPORT_SERVER;
}

ECode UnregisterExportObject(
    /* [in] */ oid_t oid)
{
    AuraCriticalSection_Enter(g_exportTableLock);
    ExportObject* pHead = s_hashExportObjects + ROT_HASH_GETOIDINDEX(oid);
    ExportObject* pPrev = NULL;

    for (ExportObject* pIter = pHead; NULL != pIter; \
        pIter = (ExportObject*)(pIter->Next())) {
        if (pIter->m_oid == oid) {
            if ((Int32)(((CObjectStub*)(pIter->m_pIStub))->m_cRefs) != 0) {
                AuraCriticalSection_Leave(g_exportTableLock);
                return S_FALSE;
            }

            pIter->m_oid = 0;
            if (pIter != pHead) {
                pIter->Detach(pPrev);
                delete pIter;
            }
            AuraCriticalSection_Leave(g_exportTableLock);
            return NOERROR;
        }
        pPrev = pIter;
    }

    AuraCriticalSection_Leave(g_exportTableLock);
    return E_NO_EXPORT_SERVER;
}

ECode RegisterImportObject(
    /* [in] */ oid_t oid,
    /* [in] */ IProxy *pIProxy)
{
    ImportObject * pObjNode;

    pObjNode = new ImportObject;
    if (NULL == pObjNode) {
        return E_OUT_OF_MEMORY;
    }
    pObjNode->m_oid = oid;
    pObjNode->m_pIProxy = pIProxy;
    AuraCriticalSection_Enter(g_exportTableLock);
    s_hashImportObjects[ROT_HASH_GETOIDINDEX(oid)].InsertFirst(pObjNode);
    AuraCriticalSection_Leave(g_exportTableLock);

    return NOERROR;
}

ECode FindImportObject(
    /* [in] */ oid_t oid,
    /* [out] */ ImportObject *pImport)
{
    AuraCriticalSection_Enter(g_exportTableLock);
    ImportObject* pHead = s_hashImportObjects + ROT_HASH_GETOIDINDEX(oid);

    for (ImportObject* pIter = pHead; NULL != pIter; \
        pIter = (ImportObject*)(pIter->Next())) {
        if (pIter->m_oid == oid) {
            memcpy(pImport, pIter, sizeof(ImportObject));
            pImport->m_pIProxy->AddRef();
            AuraCriticalSection_Leave(g_exportTableLock);
            return NOERROR;
        }
    }

    AuraCriticalSection_Leave(g_exportTableLock);
    return E_NO_IMPORT_SERVER;
}

// BUGBUG: must atomic operation with delete proxy
ECode UnregisterImportObject(
    /* [in] */ oid_t oid)
{
    AuraCriticalSection_Enter(g_exportTableLock);
    ImportObject* pHead = s_hashImportObjects + ROT_HASH_GETOIDINDEX(oid);
    ImportObject* pPrev = NULL;

    for (ImportObject* pIter = pHead; NULL != pIter; \
        pIter = (ImportObject*)(pIter->Next())) {
        if (pIter->m_oid == oid) {
            if ((Int32)(((CObjectProxy *)(pIter->m_pIProxy))->m_cRefs) != 0) {
                AuraCriticalSection_Leave(g_exportTableLock);
                return S_FALSE;
            }

            pIter->m_oid = 0;
            if (pIter != pHead) {
                pIter->Detach(pPrev);
                delete pIter;
            }

            AuraCriticalSection_Leave(g_exportTableLock);
            return NOERROR;
        }
        pPrev = pIter;
    }

    AuraCriticalSection_Leave(g_exportTableLock);
    return E_NO_IMPORT_SERVER;
}
